﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

namespace ObjectModel.Excel.Old
{
    /// <summary>
    /// Extends an Excel range object to provide events.
    /// </summary>
    public class ObservableRange : ObservableRangeBase
    {
        private dynamic mPrevValue;
        private WorksheetEvents mWorksheetEvents;

        public override Range Range
        {
            get { return base.Range; }
            set
            {
                base.Range = value;
                
                mPrevValue = Value;
                
                // Note: it is safe to subscribe this class to the events of a single worksheet
                // as the worksheet property of an Excel range never changes, even if the
                // physical range it originally referred to is moved to another worksheet/workbook.
                mWorksheetEvents = AppEvents.Worksheets[Worksheet];
                mWorksheetEvents.Subscribe(this);
            }
        }

        public override dynamic Value
        {
            get { return base.Value; }
            set
            {
                // Disable events while assigning value.
                mWorksheetEvents.Enabled = false;
                base.Value = value;
                mWorksheetEvents.Enabled = true;
            }
        }

        // Parameterless constructor for serialization.
        public ObservableRange() : base() { }

        public ObservableRange(Range range) : base(range) { }

        public void OnWorksheetChanged()
        {
            string currAddress = null;

            // Check to see if range is still valid.
            try { currAddress = Range.Address; }
            catch (COMException)
            {
                RangeChangedEventArgs e = new RangeChangedEventArgs(RangeChangedType.Deleted);

                OnRangeChanged(e);
                if (!e.Undone)
                    mWorksheetEvents.Unsubscribe(this);

                return;
            }
            
            if (currAddress != LastAddress)
            {
                RangeChangedEventArgs e = new RangeChangedEventArgs(RangeChangedType.Moved);
                
                OnRangeChanged(e);
                if (!e.Undone)
                    LastAddress = currAddress;
            }
            
            if (Range.Value != mPrevValue)
            {
                RangeChangedEventArgs e = new RangeChangedEventArgs(RangeChangedType.ValueChanged);

                OnRangeChanged(e);
                if (!e.Undone)
                    mPrevValue = Range.Value;
            }
            
        }
    }
}
